package com.sleet.yuemiao.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.io.Charsets;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.ws.rs.core.MediaType;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * HTTP请求工具类
 * 
 * @author yangjianwu
 *
 */
@Slf4j
public class HttpUtil {

	public static final String METHOD_GET = "get";

	public static final String METHOD_POST = "post";

	public static final String PARAM_TYPE_JSON = MediaType.APPLICATION_JSON;

	public static final String PARAM_TYPE_FORM = MediaType.APPLICATION_FORM_URLENCODED;

	public static HttpClient getHttpClient() {
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();
		return HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
	}

	public static String request(String url) {
		return request(url, METHOD_GET, null, PARAM_TYPE_FORM);
	}

	public static String request(HttpClient httpClient, String url) {
		return request(httpClient, url, METHOD_GET, null, PARAM_TYPE_FORM, null, null);
	}

	public static String request(String url, BasicHeader[] headers) {
		return request(null, url, METHOD_GET, null, PARAM_TYPE_FORM, headers, null);
	}

	public static String request(String url, String method, BasicHeader[] headers) {
		return request(null, url, method, null, PARAM_TYPE_FORM, headers, null);
	}

	public static String request(HttpClient httpClient, String url, BasicHeader[] headers) {
		return request(httpClient, url, METHOD_GET, null, PARAM_TYPE_FORM, headers, null);
	}

	public static <T> T request(String url, Object param) {
		return request(null, url, METHOD_GET, param, PARAM_TYPE_FORM, null, null);
	}

	public static String request(String url, String method, Object param) {
		return request(url, method, param, PARAM_TYPE_FORM);
	}

	public static String request(String url, String method, Object param, BasicHeader[] headers) {
		return request(url, method, param, PARAM_TYPE_FORM);
	}

	public static String request(HttpClient httpClient, String url, String method, Object param) {
		return request(httpClient, url, method, param, PARAM_TYPE_FORM, null, null);
	}

	public static String request(HttpClient httpClient, String url, String method, Object param,
			BasicHeader[] headers) {
		return request(httpClient, url, method, param, PARAM_TYPE_FORM, headers, null);
	}

	public static String request(String url, String method, Object param, String paramType) {
		return request(null, url, method, param, paramType, null, null);
	}

	public static String request(HttpClient httpClient, String url, String method, Object param, String paramType) {
		return request(httpClient, url, method, param, paramType, null, null);
	}

	public static String request(String url, String method, Object param, String paramType, BasicHeader[] headers) {
		return request(null, url, method, param, paramType, headers, null);
	}

	public static String postForm(String url, Object param) {
		return request(null, url, METHOD_POST, param, PARAM_TYPE_FORM, null, null);
	}

	public static String postJson(String url, Object param) {
		return request(null, url, METHOD_POST, param, PARAM_TYPE_JSON, null, null);
	}

	public static String getForm(String url, Object param) {
		return request(null, url, METHOD_GET, param, PARAM_TYPE_FORM, null, null);
	}

	public static String getJson(String url, Object param) {
		return request(null, url, METHOD_GET, param, PARAM_TYPE_JSON, null, null);
	}

	public static byte[] postJson2Bytes(String url, Object param) throws UnsupportedEncodingException {
		ResponseHandler<byte[]> httpHandler = bytesHandler();

		return request(null, url, METHOD_POST, param, PARAM_TYPE_JSON, null, httpHandler);
	}

	public static byte[] getBytes(String url) throws UnsupportedEncodingException {
		ResponseHandler<byte[]> httpHandler = bytesHandler();

		return request(null, url, METHOD_GET, null, PARAM_TYPE_FORM, null, httpHandler);
	}

	public static byte[] getBytes(String url, Object param) throws UnsupportedEncodingException {
		ResponseHandler<byte[]> httpHandler = bytesHandler();

		return request(null, url, METHOD_POST, param, PARAM_TYPE_FORM, null, httpHandler);
	}

	public static <T> T request(HttpClient httpClient, String url, String method, Object param, String paramType,
			BasicHeader[] headers, ResponseHandler<T> httpHandler) {
		log.info("请求路径：【{}】",url);
		try {
			if (httpHandler == null) {
				httpHandler = handler();
			}

			// client config
			RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();
			if (httpClient == null) {
				httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
			}
			RequestConfig localConfig = RequestConfig.copy(globalConfig).setCookieSpec(CookieSpecs.STANDARD_STRICT)
					.setProxy(new HttpHost("159.75.75.191",5438))
					.build();

			if (METHOD_POST.equals(method)) {
				HttpPost request = new HttpPost(url);

				request.setConfig(localConfig);

				if (PARAM_TYPE_JSON.equals(paramType)) {
					if (param != null) {
						String jsonParam = JsonUtil.toString(param);
						StringEntity jsonEntity = new StringEntity(jsonParam,
								ContentType.create(PARAM_TYPE_JSON, Charsets.UTF_8));
						request.setEntity(jsonEntity);
					}
				} else if (MediaType.APPLICATION_XML.equals(paramType)) {
					StringEntity jsonEntity = new StringEntity(String.valueOf(param),
							ContentType.create(MediaType.APPLICATION_XML, Charsets.UTF_8));
					request.setEntity(jsonEntity);
				} else {
					List<NameValuePair> formparams = new ArrayList<NameValuePair>();

					Map<String, Object> paramMap = new HashedMap();

					if (param != null) {
						if (param instanceof Map) {
							paramMap = (Map<String, Object>) param;
						} else {
							paramMap = JsonUtil.toMap(JsonUtil.toString(param));
						}
					}

					Iterator<Entry<String, Object>> entryIterator = paramMap.entrySet().iterator();
					while (entryIterator.hasNext()) {
						Entry<String, Object> entry = entryIterator.next();
						formparams.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
					}
					UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "utf-8");

					request.setEntity(entity);
				}

				if (headers != null && headers.length > 0) {
					request.setHeaders(headers);
				}

				return httpClient.execute(request, httpHandler);
			} else {
				if (param != null) {
					if (PARAM_TYPE_JSON.equals(paramType)) {
						url = url + "?" + JsonUtil.toString(param);
					} else {
						url = url + "?" + parseFormParam(param);
					}
				}

				HttpGet request = new HttpGet(url);
				request.setConfig(localConfig);

				if (headers != null && headers.length > 0) {
					request.setHeaders(headers);
				}
				T execute = httpClient.execute(request, httpHandler);
				return execute;
			}
		} catch (Exception e) {
			log.error("第三方请求失败，失败原因:{}", e);
			throw new IllegalArgumentException("http request error");
		}
	}


	private static String parseFormParam(Object param) {
		try {
			Map<String, Object> paramMap = null;

			if (param instanceof Map) {
				paramMap = (Map<String, Object>) param;
			} else {
				paramMap = JsonUtil.toMap(JsonUtil.toString(param));
			}

			StringBuilder formParams = new StringBuilder();
			Iterator<Entry<String, Object>> entryIterator = paramMap.entrySet().iterator();
			while (entryIterator.hasNext()) {
				Entry<String, Object> entry = entryIterator.next();
				String val = "";
				Object value = entry.getValue();
				if (value != null) {
					if (value instanceof String) {
						val = String.valueOf(value);
					} else {
						val = JsonUtil.toString(value);
					}

					try {
						formParams.append(entry.getKey()).append("=").append(URLEncoder.encode(val, "utf-8"))
								.append("&");
					} catch (UnsupportedEncodingException e) {
						log.error("{}",e);
					}
				}
			}

			return StringUtils.chop(formParams.toString());
		} catch (Exception e) {
			return "";
		}
	}

	public static <T> ResponseHandler<T> handler() {
		ResponseHandler<T> loginHandler = new ResponseHandler<T>() {
			@SuppressWarnings("unchecked")
			@Override
			public T handleResponse(final HttpResponse response) throws IOException {
				StatusLine statusLine = response.getStatusLine();
				HttpEntity entity = response.getEntity();
				if (statusLine.getStatusCode() >= 300) {
					throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
				}
				if (entity == null) {
					throw new ClientProtocolException("Response contains no content");
				}
				entity = new BufferedHttpEntity(entity);
				String responseAsString = EntityUtils.toString(entity, "UTF-8");
				return (T) responseAsString;
			}
		};
		return loginHandler;
	}

	public static ResponseHandler<byte[]> bytesHandler() {
		ResponseHandler<byte[]> loginHandler = new ResponseHandler<byte[]>() {
			@SuppressWarnings("unchecked")
			@Override
			public byte[] handleResponse(final HttpResponse response) throws IOException {
				StatusLine statusLine = response.getStatusLine();
				HttpEntity entity = response.getEntity();
				if (statusLine.getStatusCode() >= 300) {
					throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
				}
				if (entity == null) {
					throw new ClientProtocolException("Response contains no content");
				}
				entity = new BufferedHttpEntity(entity);

				return EntityUtils.toByteArray(entity);
			}
		};
		return loginHandler;
	}

	public static String upload(String url, Map param, byte[] fb) throws Exception {
		ResponseHandler<String> httpHandler = handler();
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();
		HttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();

		RequestConfig localConfig = RequestConfig.copy(globalConfig).setCookieSpec(CookieSpecs.STANDARD_STRICT).build();

		HttpPost request = new HttpPost(url);
		request.setConfig(localConfig);

		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().addBinaryBody("file", fb,
				ContentType.TEXT_PLAIN, "file.csv");

		param.forEach((k, v) -> {
			multipartEntityBuilder.addTextBody(String.valueOf(k), String.valueOf(v),
					ContentType.APPLICATION_FORM_URLENCODED);
//			multipartEntityBuilder.addPart(FormBodyPartBuilder.create(String.valueOf(k),
//					new StringBody(String.valueOf(v), ContentType.APPLICATION_FORM_URLENCODED)).build());
		});

		HttpEntity reqEntity = multipartEntityBuilder.build();

		request.setEntity(reqEntity);

		return httpClient.execute(request, httpHandler);
	}

	/*public static String upload(String url, byte[] fb, ContentType contentType, String filename) throws Exception {
		ResponseHandler<String> httpHandler = handler();
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();
		HttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();

		RequestConfig localConfig = RequestConfig.copy(globalConfig).setCookieSpec(CookieSpecs.STANDARD_STRICT).build();

		HttpPost request = new HttpPost(url);
		request.setConfig(localConfig);

		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().addBinaryBody(filename.split("\\.")[0], fb,
				contentType, filename);

		HttpEntity reqEntity = multipartEntityBuilder.build();
		request.setEntity(reqEntity);
		return httpClient.execute(request, httpHandler);
	}*/

	public static String upload(String url, File file) throws Exception {
		ResponseHandler<String> httpHandler = handler();
		RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();
		HttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
		RequestConfig localConfig = RequestConfig.copy(globalConfig).setCookieSpec(CookieSpecs.STANDARD_STRICT).build();
		HttpPost request = new HttpPost(url);
		request.setConfig(localConfig);
		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
				.addPart("file", new FileBody(file))
				.addPart("comment", new StringBody("comment", ContentType.TEXT_PLAIN));
		HttpEntity reqEntity = multipartEntityBuilder.build();
		request.setEntity(reqEntity);
		return httpClient.execute(request, httpHandler);
	}

	/**
	 * post方式传输文件
	 *
	 * @param urlStr
	 * @param textMap
	 * @param buffer
	 * @param contentType
	 * @return
	 */
//	public static String postFormData(String urlStr, Map<String, String> textMap, byte[] buffer, String fileName, String contentType) {
//		String res = "";
//		HttpURLConnection conn = null;
//		// boundary就是request头和上传文件内容的分隔符
//		String BOUNDARY = "---------------------------123821742118716";
//		try {
//			URL url = new URL(urlStr);
//			conn = (HttpURLConnection) url.openConnection();
//			conn.setConnectTimeout(5000);
//			conn.setReadTimeout(30000);
//			conn.setDoOutput(true);
//			conn.setDoInput(true);
//			conn.setUseCaches(false);
//			conn.setRequestMethod("POST");
//			conn.setRequestProperty("Connection", "Keep-Alive");
//			conn.setRequestProperty("User-Agent",
//					"Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
//			conn.setRequestProperty("Content-Type",
//					"multipart/form-data; boundary=" + BOUNDARY);
//			OutputStream out = new DataOutputStream(conn.getOutputStream());
//			// text
//			if (textMap != null) {
//				StringBuffer strBuf = new StringBuffer();
//				Iterator iter = textMap.entrySet().iterator();
//				while (iter.hasNext()) {
//					Map.Entry entry = (Map.Entry) iter.next();
//					String inputName = (String) entry.getKey();
//					String inputValue = (String) entry.getValue();
//					if (inputValue == null) {
//						continue;
//					}
//					strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
//					strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n");
//					strBuf.append(inputValue);
//				}
//				out.write(strBuf.toString().getBytes());
//			}
//			// file
//			if (buffer != null) {
//				if (contentType == null || "".equals(contentType)) {
//					contentType = "application/octet-stream";
//				}
//				StringBuffer strBuf = new StringBuffer();
//				strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
//				strBuf.append("Content-Disposition: form-data; name=\""
//						+ fileName + "\"; filename=\"" + fileName + "\"; filelength=\"" + buffer.length + "\"\r\n");
//				strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
//				out.write(strBuf.toString().getBytes());
//
//				InputStream in = new ByteArrayInputStream(buffer);
//				int bytes = 0;
//				byte[] bufferOut = new byte[1024];
//				while ((bytes = in.read(bufferOut)) != -1) {
//					out.write(bufferOut, 0, bytes);
//				}
//				in.close();
//			}
//			byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
//			out.write(endData);
//			out.flush();
//			out.close();
//			// 读取返回数据
//			StringBuffer strBuf = new StringBuffer();
//			BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
//			String line = null;
//			while ((line = reader.readLine()) != null) {
//				strBuf.append(line).append("\n");
//			}
//			res = strBuf.toString();
//			reader.close();
//			reader = null;
//		} catch (IOException e) {
//			throw new RuntimeException(e);
//		} finally {
//			if (conn != null) {
//				conn.disconnect();
//				conn = null;
//			}
//		}
//		return res;
//	}
}
